package com.lichuang.fruitvarietysm.order.controller;

import com.alibaba.fastjson.JSON;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.lichuang.fruitvarietysm.order.config.AlipayConfig;
import com.lichuang.fruitvarietysm.order.entity.*;
import com.lichuang.fruitvarietysm.order.enums.OrderStatus;
import com.lichuang.fruitvarietysm.order.feignclient.GoodsFeignClient;
import com.lichuang.fruitvarietysm.order.feignclient.ShopingCartFeignClient;
import com.lichuang.fruitvarietysm.order.feignclient.UserFeignClient;
import com.lichuang.fruitvarietysm.order.mapper.OrderDtlMapper;
import com.lichuang.fruitvarietysm.order.mapper.UserOrderMapper;
import com.lichuang.fruitvarietysm.order.service.IUserOrderService;
import com.lichuang.fruitvarietysm.order.service.impl.UserOrderServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 订单表 前端控制器
 * </p>
 *
 * @author shuaihang
 * @since 2019-06-17
 */
@RestController
@RequestMapping(value = "//order")
public class OrderController {

    @Autowired
    private UserOrderMapper orderMapper;

    @Autowired
    private OrderDtlMapper orderDtlMapper;

    @Autowired
    private UserOrderServiceImpl orderService;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private GoodsFeignClient goodsFeignClient;

    @Autowired
    private ShopingCartFeignClient shopingCartFeignClient;


    /**
     * 分页查询订单信息
     *
     * @param page  分页条件
     *              current:当前是第几页
     *              size:每页显示的数量
     *              total（不用设置）:总数
     * @param order 查询条件，将条件放入实体类中即可
     * @return
     */
    @RequestMapping("/getOrder")
    public IPage<UserOrder> getOrder(Page page, UserOrder order, @CookieValue(value = "loginToken") String loginToken) {
        User user = userFeignClient.getCurrentUser(loginToken);
        if (user == null) {
            return null;
        }
        order.setUserId(user.getUserId());
        IPage<UserOrder> orderPage = orderService.getOrder(page, order);
        // 循环分页后的记录，给每一条记录设置sku的文本
        for (UserOrder record : orderPage.getRecords()) {
            // 调用了goods模块的方法，得到skuText
            List<List> skuText = goodsFeignClient.getSkuText(record.getOrderDtl().getSkuId());
            record.getOrderDtl().setSkuText(skuText);
        }
        return orderPage;
    }

    /**
     * 生成订单号
     * 生成规则：当前时间戳 + 用户id后两位(id不足2位的在前面补0) + 3位随机数
     *
     * @param userId
     * @return
     */
    public String createOrderNo(Integer userId) {
        String userIdString = Integer.toString(userId);
        String processUserId;
        if (userIdString.length() >= 2) {
            processUserId = userIdString.substring(userIdString.length() - 2);
        } else {
            processUserId = "0" + userIdString;
        }
        StringBuilder orderNo = new StringBuilder();
        Integer random = (int) (Math.random() * 900 + 100);
        orderNo.append(System.currentTimeMillis())
                .append(processUserId)
                .append(random);
        return orderNo.toString();
    }


    /**
     * 在购物车点击结算生成订单信息
     * 首先通过购物车id拿到购物车，将购物车的goodsId和skuId存入订单详情中，将每次循环的订单详情存入数组
     * 最后调用{@link #createOrderInfo(List)}来拿到订单详情的其他信息
     *
     * @param cartId
     * @param loginToken
     * @return
     */
    @RequestMapping("/clearing")
    public List<OrderDtl> clearing(@RequestParam(value = "cartId[]") Integer[] cartId, @CookieValue("loginToken") String loginToken) {
        List<OrderDtl> orderDtls = new ArrayList<>();
        for (int i = 0; i < cartId.length; i++) {
            // 拿到一条购物车的信息
            Shoppingcart shoppingcart = shopingCartFeignClient.getOneShppingCart(loginToken, cartId[i]);
            Integer skuId = shoppingcart.getSkuId();
            Integer goodsId = shoppingcart.getGoodsId();
            OrderDtl orderDtl = new OrderDtl();
            orderDtl.setSkuId(skuId)
                    .setGoodsId(goodsId)
                    .setQuantity(shoppingcart.getQuantity());
            orderDtls.add(orderDtl);
        }
        return createOrderInfo(orderDtls);
    }

    /**
     * 生成订单信息
     *
     * @param orderDtls
     * @return
     */
    @RequestMapping("/createOrderInfo")
    public List<OrderDtl> createOrderInfo(@RequestBody List<OrderDtl> orderDtls) {
        for (OrderDtl orderDtl : orderDtls) {
            Goods goods = goodsFeignClient.getGoods(orderDtl.getGoodsId());
            Goodssku goodssku = goodsFeignClient.getSkuBySkuId(orderDtl.getSkuId());
            // 商品主图
            orderDtl.setMainImage(goods.getMainImage());
            // 商品名称
            orderDtl.setGoodsName(goods.getGoodsName());
            // 单价,如果商品是sku就是sku的价格，否则就是商品价格
            if (goods.getIsSku() == 2) {
                orderDtl.setCurrentGoodsPrice(goods.getGoodsPrice());
            } else {
                orderDtl.setCurrentGoodsPrice(goodssku.getGoodsPrice());
                // sku文本
                orderDtl.setSkuText(goodsFeignClient.getSkuText(orderDtl.getSkuId()));
            }
            // 商品总价
            BigDecimal totalPrice = orderDtl.getCurrentGoodsPrice().multiply(new BigDecimal(orderDtl.getQuantity()));
            orderDtl.setTotalPrice(totalPrice);
        }
        return orderDtls;
    }

    // 计算价格
    public BigDecimal calculatePrice(BigDecimal price, Integer buyNumber) {
        // 商品单价 * 数量 + 运费 - 优惠
        return price.multiply(new BigDecimal(buyNumber)).add(new BigDecimal("0")).subtract(new BigDecimal("0"));
    }


    /**
     * 生成一个订单
     * 前端需要传入：收货地址id,实际付款金额,支付类型,运费;参考{@link UserOrder}
     * 商品id,商品skuId,生成订单时商品单价,商品数量,商品总价;参考{@link UserOrder#orderDtl}
     * 后端根据商品skuId获取商品单价，根据商品数量计算商品总价；
     * 将计算出来的价格和前端传过来的价格对比，如果不一致说明此订单有问题
     * 一致将生成订单
     *
     * @param loginToken
     */
    @PostMapping("/createOrder")
    public void createOrder(@RequestBody List<UserOrder> orders, Integer[] cartId, @CookieValue(value = "loginToken") String loginToken, HttpServletRequest request, HttpServletResponse response) throws IOException {
        User user = userFeignClient.getCurrentUser(loginToken);
        if (user == null) {
            return;
        }

        for (UserOrder order : orders) {
            /**
             * 通过skuId拿到库存和价格
             * 如果 购买数量 > 库存，返回
             * 计算总价，和前端传来的总价进行对比
             */
            Goodssku goodssku = goodsFeignClient.getSkuBySkuId(order.getOrderDtl().getSkuId());
            Goods goods = goodsFeignClient.getGoods(order.getOrderDtl().getGoodsId());
            // 商品的库存量
            Integer number;
            // 用户要购买的数量
            Integer buyNumber = order.getOrderDtl().getQuantity();
            // 商品的单价
            BigDecimal price = new BigDecimal(0);
            if (goods.getIsSku() == 2) {
                price = goods.getGoodsPrice();
                number = goods.getGoodsStock();
            } else {
                price = goodssku.getGoodsPrice();
                number = goodssku.getNumber();
            }
            if (buyNumber > number) {
                // 库存不足
                return;
            }
            // 减去库存
            if (goods.getIsSku() == 2) {
                goods.setGoodsStock(number - buyNumber);
            } else {
                goodssku.setNumber(number - buyNumber);
            }
            // 得到实际付款金额
            BigDecimal payment = calculatePrice(price, buyNumber);
            // 比较实际付款金额和前端传来的付款金额,结果为0代表相等
//            if (payment.compareTo(order.getPayment()) != 0) {
//                // 价钱不一致
//                return;
//            }
            Integer userId = user.getUserId();
            // 订单号
            String orderNo;
            // 此订单号在数据库中的数量
            Integer count;
            // 生产订单号，如果有重复就继续循环
            do {
                orderNo = createOrderNo(userId);
                UserOrder orderParam = new UserOrder();
                orderParam.setOrderNo(Long.valueOf(orderNo));
                count = orderMapper.selectCount(new QueryWrapper<>(orderParam));
            } while (count >= 1);

            // 往订单中存入信息
            order.setUserId(userId)
                    .setOrderNo(Long.valueOf(orderNo))
                    .setCreateTime(LocalDateTime.now())
                    .setPayment(payment);
            order.getOrderDtl().setUserId(userId)
                    .setGoodsName(goods.getGoodsName())
                    .setCurrentGoodsPrice(price)
                    .setOrderNo(Long.valueOf(orderNo))
                    .setCreateTime(LocalDateTime.now());
            addOrder(order, goodssku, cartId, goods);
        }
        payment(orders, request, response);
    }

    // 减库存，将订单插入订单表,删除购物车中的商品
    @Transactional
    public void addOrder(UserOrder order, Goodssku goodssku, Integer[] cartId, Goods goods) {
        if (goods.getIsSku() == 2){
            // 减库存,调用goods模块的方法
            goodsFeignClient.updateGoods(goods);
        }else {
            // 减库存,调用goods模块的方法
            goodsFeignClient.updateSku(goodssku);
        }
        // 插入订单表
        orderMapper.insert(order);
        // 插入订单详情表
        orderDtlMapper.insert(order.getOrderDtl());
        // 删除购物车
        shopingCartFeignClient.deleteOrderCartGoods(cartId);
    }

    // 支付
    public void payment(List<UserOrder> orders, HttpServletRequest request, HttpServletResponse response) throws IOException {
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id, AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key, AlipayConfig.sign_type);
        AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();//创建API对应的request
        String notify_url = AlipayConfig.notify_url;
        String retuen_utl = AlipayConfig.return_url;
        alipayRequest.setReturnUrl(retuen_utl);
        alipayRequest.setNotifyUrl(notify_url);//在公共参数中设置回跳和通知地址
        StringBuilder orderNo = new StringBuilder();
        BigDecimal payment = new BigDecimal(0);
        StringBuilder subject = new StringBuilder();
        for (UserOrder order : orders) {
            if (!orderNo.toString().equals("")) {
                orderNo.append("_");
            }
            orderNo.append(order.getOrderNo());
            payment = payment.add(order.getPayment());
            subject.append(order.getOrderDtl().getGoodsName());
        }

        alipayRequest.setBizContent("{" +
                "    \"out_trade_no\":\"" + orderNo + "\"," +
                "    \"product_code\":\"FAST_INSTANT_TRADE_PAY\"," +
                "    \"total_amount\":" + payment + "," +
                "    \"subject\":\"" + subject + "\"," +
                "    \"body\":\"this is test body\"," +
                "    \"passback_params\":\"merchantBizType%3d3C%26merchantBizNo%3d2016010101111\"," +
                "    \"extend_params\":{" +
                "    \"sys_service_provider_id\":\"2088511833207846\"" +
                "    }" +
                "  }");//填充业务参数
        String form = "";
        try {
            form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        response.setContentType("text/html;charset=" + AlipayConfig.charset);
        response.getWriter().write(form);//直接将完整的表单html输出到页面
        response.getWriter().flush();
        response.getWriter().close();
    }

    @RequestMapping("/alipayNotifyUrl")
    public void alipayNotifyUrl(HttpServletRequest request, HttpServletResponse response) throws IOException, AlipayApiException {
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用
//            valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }

        boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //调用SDK验证签名

        //——请在这里编写您的程序（以下代码仅作参考）——

	/* 实际验证过程建议商户务必添加以下校验：
	1、需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号，
	2、判断total_amount是否确实为该订单的实际金额（即商户订单创建时的金额），
	3、校验通知中的seller_id（或者seller_email) 是否为out_trade_no这笔单据的对应的操作方（有的时候，一个商户可能有多个seller_id/seller_email）
	4、验证app_id是否为该商户本身。
	*/
        PrintWriter out = response.getWriter();

        if (signVerified) {//验证成功
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");

            String[] orderNo = out_trade_no.split("_");

            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");

            //交易状态
            String trade_status = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"), "UTF-8");

            // 交易总金额
            String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8");

            // seller_id
            String seller_id = new String(request.getParameter("seller_id").getBytes("ISO-8859-1"), "UTF-8");

            // app_id
            String app_id = new String(request.getParameter("app_id").getBytes("ISO-8859-1"), "UTF-8");

            if (trade_status.equals("TRADE_FINISHED")) {
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
                //如果有做过处理，不执行商户的业务程序

                //注意：
                //退款日期超过可退款期限后（如三个月可退款），支付宝系统发送该交易状态通知
            } else if (trade_status.equals("TRADE_SUCCESS")) {
                //判断该笔订单是否在商户网站中已经做过处理
                //如果没有做过处理，根据订单号（out_trade_no）在商户网站的订单系统中查到该笔订单的详细，并执行商户的业务程序
                //如果有做过处理，不执行商户的业务程序

                //注意：
                //付款完成后，支付宝系统发送该交易状态通知

                if (!seller_id.equals(AlipayConfig.seller_id)) {
                    return;
                }
                if (!app_id.equals(AlipayConfig.app_id)) {
                    return;
                }

                List<UserOrder> orders = new ArrayList<>();
                BigDecimal payment = new BigDecimal(0);
                for (int i = 0; i < orderNo.length; i++) {
                    UserOrder orderParam = new UserOrder();
                    orderParam.setOrderNo(Long.valueOf(orderNo[i]));
                    QueryWrapper queryWrapper = new QueryWrapper(orderParam);
                    Integer count = orderMapper.selectCount(queryWrapper);
                    UserOrder order = orderMapper.selectOne(queryWrapper);
                    if (count == 0) {
                        // 该通知数据中的 out_trade_no 是否为商户系统中创建的订单号
                        return;
                    } else {
                        orders.add(order);
                        payment = payment.add(order.getPayment());
                    }
                }
                if (payment.compareTo(new BigDecimal(total_amount)) != 0) {
                    // 判断 total_amount 是否确实为该订单的实际金额（即商户订单创建时的金额）
                    return;
                }
                for (UserOrder order : orders) {
                    order.setOrderStatus(OrderStatus.WAIT_SELLER_DELIVERY.getValue())
                            .setPaymentTime(LocalDateTime.now());
                    orderService.updateUserOrderById(order);
                }
            }
            out.println("success");
        } else {//验证失败
            out.println("fail");
            //调试用，写文本函数记录程序运行情况是否正常
            //String sWord = AlipaySignature.getSignCheckContentV1(params);
            //AlipayConfig.logResult(sWord);
        }
        //——请在这里编写您的程序（以上代码仅作参考）——
    }

    @RequestMapping("/alipayReturnUrl")
    public ModelAndView alipayReturnUrl(HttpServletRequest request) throws IOException, AlipayApiException {
        //该页面仅做页面展示，业务逻辑处理请勿在该页面执行
        //获取支付宝GET过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            //乱码解决，这段代码在出现乱码时使用
            valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
            params.put(name, valueStr);
        }

        boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type); //调用SDK验证签名

//        PrintWriter out = response.getWriter();

        ModelAndView modelAndView = new ModelAndView();

        //——请在这里编写您的程序（以下代码仅作参考）——
        if (signVerified) {
            //商户订单号
            String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");

            String[] orderNo = out_trade_no.split("_");

            //支付宝交易号
            String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");

            //付款金额
            String total_amount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8");

            UserOrder orderParam = new UserOrder();
            orderParam.setOrderNo(Long.valueOf(orderNo[0]));
            UserOrder order = orderMapper.selectOne(new QueryWrapper<>(orderParam));
            String shipping_address_text = userFeignClient.getShippingAddressTextById(order.getShippingId());

            modelAndView.addObject("shippingAddress", shipping_address_text);
            modelAndView.addObject("payment", total_amount);
            modelAndView.setViewName("aliPayReturnUrl");
            return modelAndView;
//            out.println("trade_no:" + trade_no + "<br/>out_trade_no:" + out_trade_no + "<br/>total_amount:" + total_amount);
        } else {
            modelAndView.setViewName("aliPayReturnUrl");
            return modelAndView;
//            out.println("验签失败");
        }
        //——请在这里编写您的程序（以上代码仅作参考）——
    }

}
